﻿using KSASupport;
using KSASupport.Imaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace KSACalibrate
{
    public enum DebugWindowMode { Raw, Threshold, Calibrating,CalibratedImage,HoverThreshold,Analysis}
    /// <summary>
    /// Interaction logic for CalibrationWindow.xaml
    /// </summary>
    public partial class CalibrationWindow : UserControl
    {
        private DebugWindowMode mode;

        private DepthManager depthManager;

        public DepthManager DepthManager
        {
            get { return depthManager; }
            set { depthManager = value; }
        }

        private bool InteropBitmapInitialized = false;
        private InteropBitmapHelper interopBitmapHelper;
        private DispatcherTimer timer;
        
        public void SetMode(DebugWindowMode mode)
        {
            this.mode = mode;
        }

        public CalibrationWindow(DepthManager depthManager)
        {
            InitializeComponent();
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(30);
            timer.Tick += timer_Tick;

            this.depthManager = depthManager;
            mode = DebugWindowMode.Raw;
        }

        public void StartRendering()
        {
            timer.Start();
        }

        public void StopRendering()
        {
            timer.Stop();
        }
        void timer_Tick(object sender, EventArgs e)
        {
            byte[] image = new byte[0];
            switch(mode)
            {
                case DebugWindowMode.Raw :
                    {
                        image = KinectImageConversion.ConvertShortToByteImage(depthManager.RawDepthValues, depthManager.DepthImageWidth, depthManager.DepthImageHeight);                        
                        break;
                    }
                case DebugWindowMode.Threshold :
                    {                        
                        image = KinectImageConversion.ConvertintToByteImage(depthManager.ThresholdImage, depthManager.DepthImageWidth, depthManager.DepthImageHeight,7,15);
                        break;
                    }
                case DebugWindowMode.HoverThreshold:
                    {
                        image = KinectImageConversion.ConvertintToByteImage(depthManager.HoveringThresholdImage, depthManager.DepthImageWidth, depthManager.DepthImageHeight, 0, 4000);
                        break;
                    }
                case DebugWindowMode.CalibratedImage:
                    {
                        image = KinectImageConversion.ConvertintToByteImage(depthManager.CalibratedDepthValues, depthManager.DepthImageWidth, depthManager.DepthImageHeight, 7, 15);
                        break;
                    }
                case DebugWindowMode.Analysis:
                    {
                        image = LoadAnalysisImage();
                        break;
                    }
                case DebugWindowMode.Calibrating:
                    {
                        if(!depthManager.IsCalibrated)
                        {
                            image = depthManager.CalibrationImage;
                        }
                        else
                        {
                            mode = DebugWindowMode.CalibratedImage;
                        }
                        
                        break;
                    }
            }

            if ((image != null) && (image.Length > 0))
            {
                RenderImage(DebugImage, image);
            }
        }

        private byte[] LoadAnalysisImage()
        {
            byte[] image = new byte[depthManager.DepthImageWidth * depthManager.DepthImageHeight * 4];

            short[] imageValues = new short[depthManager.DepthImageWidth * depthManager.DepthImageHeight];

            int total = 0;
            int count = 0;
            for(int b = 0; b < depthManager.CalibratedDepthValues.Count();b++)
            {
                Point p = new Point();
                p.Y = b / depthManager.DepthImageWidth;
                p.X = b - (p.Y * depthManager.DepthImageWidth);
                if (IsWithinScreenCalibration(p))
                {
                    if ((depthManager.DepthManagerSettings.calibrationDistanceValues[b] != null) && (depthManager.DepthManagerSettings.calibrationDistanceValues[b].Value > 0))
                    {
                        count++;
                        total += depthManager.DepthManagerSettings.calibrationDistanceValues[b].Value;
                    }
                }                    
            }
            
            // DBZ protect
            if (count == 0)
                return image;


            int average = total / count;

            int calibrationindex = 0;
            
            for (int i = 0; i < imageValues.Length; i++)
            {
                Point p = new Point();
                p.Y = i / depthManager.DepthImageWidth;
                p.X = i - (p.Y * depthManager.DepthImageWidth);
                if (IsWithinScreenCalibration(p))
                {

                    if (depthManager.DepthManagerSettings.calibrationDistanceValues[i] != null)
                    {
                        int CalibrationValue = depthManager.DepthManagerSettings.calibrationDistanceValues[i].Value;
                        if (CalibrationValue >= average)
                        {
                            byte offset = (byte)((CalibrationValue - average) * 30);
                            image[calibrationindex] = offset;
                            image[calibrationindex + 1] = offset;
                        }
                        else
                        {
                            byte offset = (byte)((average - CalibrationValue) * 30);
                            image[calibrationindex + 1] = offset;
                            image[calibrationindex + 2] = offset;
                        }

                    }
                }
                calibrationindex += 4;    
            }

            return image;
        }
        public bool IsWithinScreenCalibration(Point p)
        {
            Rect boundaryFilterRect = depthManager.DepthManagerSettings.ScreenBoundaryRect;

            if (p.X < boundaryFilterRect.Left)
                return false;
            if (p.X > boundaryFilterRect.Right)
                return false;

            if (p.Y < boundaryFilterRect.Top)
                return false;

            if (p.Y > boundaryFilterRect.Bottom)
                return false;

            return true;
        }
        private void RenderImage(Image image, byte[] source)
        {

            if (!InteropBitmapInitialized)
            {
                interopBitmapHelper = new InteropBitmapHelper(depthManager.DepthImageWidth, depthManager.DepthImageHeight, source);
                InteropBitmapInitialized = true;
            }
            else
            {
                interopBitmapHelper.UpdateBits(source);
            }
            image.Source = interopBitmapHelper.InteropBitmap;
        }


    }
}
